﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;

namespace GArphics
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// List of the trees in the current population
        /// </summary>
        private List<Tree> _oPopulation = new List<Tree>();
        /// <summary>
        /// List of the selected pictures/trees.
        /// </summary>
        private List<int> _iSelections = new List<int>();
        private Renderer oRenderer = new Renderer();

        /// <summary>
        /// Constructor for the main for. Initializes the components and the backgroundworkers.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            pbxBigPicture.BringToFront();

            for (int i = 0; i < 20; i++)
            {
                _oPopulation.Add(new Tree(
                                            new Node(Operators.AND,
                                                                    new Node(0.4905431d),
                                                                    new Node(Operators.ABS,
                                                                                            new Node(Operators.COS,
                                                                                                                    new Node(Operators.MOD,
                                                                                                                                            new Node(Operands.Y),
                                                                                                                                            new Node(Operands.X)),
                                                                                                                    new Node(Operands.X)),
                                                                                            new Node(Operands.Y)))
                                  ));
            }

            trackBar1.Maximum = Properties.Settings.Default.AnimationStepMax;
            lblChangeValue.Text = (1 / (double)trackBar1.Value).ToString();

            oRenderer.ImageRendered += new Renderer.RenderEventHandler(oRenderer_ImageRendered);
            oRenderer.AllRenderingDone += new EventHandler(oRenderer_AllRenderingDone);
        }

        void oRenderer_AllRenderingDone(object sender, EventArgs e)
        {
            EnableControls();
        }

        private void oRenderer_ImageRendered(object sender, RenderEventArgs e)
        {
            if (e.Data.Image != null && oTablePanel.Controls.Count >= e.Data.ID && oTablePanel.Controls[e.Data.ID].Controls[0] is PictureBox)
            {
                (oTablePanel.Controls[e.Data.ID].Controls[0] as PictureBox).Image = e.Data.Image;
            }
        }

        private Bitmap DrawTree(Tree Tree, PictureBox TargetPictureBox)
        {
            Bitmap oNewImage = oRenderer.RenderOne(Tree, TargetPictureBox.Size);

            TargetPictureBox.Image = oNewImage;

            return oNewImage;
        }

        private void EnableControls()
        {
            gbxDrawing.Enabled = true;
            gbxGA.Enabled = true;
            gbxAnimate.Enabled = true;
            btnForceReDraw.Enabled = true;
            gbxCoordinates.Enabled = true;
            gbxFilters.Enabled = true;
        }

        /// <summary>
        /// Re-draws the pictures of all trees currently in the population.
        /// Sets the work for the backgroundworkers and activates them.
        /// </summary>
        private void ReDrawAll()
        {
            for (int i = 0; i < 20; i++)    //Clearing the images currently displayed on the pictureboxes
            {
                ((PictureBox)oTablePanel.Controls[i].Controls[0]).Image = null;

                oRenderer.AddWork(new RenderData(_oPopulation[i], ((PictureBox)oTablePanel.Controls[i].Controls[0]).Size, i));
            }

            btnStop.Enabled = true;
            btnForceReDraw.Enabled = false;
            gbxGA.Enabled = false;
            gbxCoordinates.Enabled = false;

            oRenderer.Start();
        }

        private void btnInitialize_Click(object sender, EventArgs e)
        {
            _oPopulation = new List<Tree>();

            ClearSelections();

            for (int iCount = 0; iCount < 20; iCount++)
            {
                _oPopulation.Add(Tree.CreateRandomTree());
            }

            ReDrawAll();
        }

        private void ClearSelections()
        {
            foreach (int iSelection in _iSelections)
            {
                ((Panel)oTablePanel.Controls[iSelection]).BackColor = BackColor;
            }

            btnCross.Enabled = false;
            btnMutate.Enabled = false;
            btnSave.Enabled = false;
            btnSaveBitmap.Enabled = false;

            _iSelections.Clear();
        }

        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            for (int i = 0; i < 20; i++)
            {
                if (oTablePanel.Controls[i].Controls[0] == sender)
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        if (_iSelections.Contains(i))
                        {
                            _iSelections.Remove(i);
                            oTablePanel.Controls[i].BackColor = BackColor;
                        }
                        else
                        {
                            _iSelections.Add(i);
                            oTablePanel.Controls[i].BackColor = Color.Red;

                            DisplayTree(_oPopulation[i]);

                            Console.WriteLine(i + ": " + _oPopulation[i].Fitness);
                        }

                        if (_iSelections.Count == 1)
                        {
                            btnAnimate.Enabled = true;
                            btnCross.Enabled = false;
                            btnMutate.Enabled = true;
                            btnSave.Enabled = true;
                            btnSaveBitmap.Enabled = true;
                        }
                        else if (_iSelections.Count == 2)
                        {
                            btnAnimate.Enabled = false;
                            btnCross.Enabled = true;
                            btnMutate.Enabled = false;
                            btnSave.Enabled = false;
                            btnSaveBitmap.Enabled = false;
                        }
                        else
                        {
                            btnAnimate.Enabled = false;
                            btnCross.Enabled = false;
                            btnMutate.Enabled = false;
                            btnSave.Enabled = false;
                            btnSaveBitmap.Enabled = false;
                        }
                    }
                    else
                    {
                        pbxBigPicture.Show();
                        DrawTree(_oPopulation[i], pbxBigPicture);
                    }
                }
            }
        }

        private void DisplayTree(Tree oTree)
        {
            oTreeView.Nodes.Clear();

            if (oTree != null && oTree.RootNode != null)
            {
                oTreeView.Nodes.Add(GetTreeViewNodes(oTree.RootNode));

                cbxRed.Checked = oTree.RedChannelModifier;
                tbrRed.Value = oTree.RedChannelValue;
                cbxGreen.Checked = oTree.GreenChannelModifier;
                tbrGreen.Value = oTree.GreenChannelValue;
                cbxBlue.Checked = oTree.BlueChannelModifier;
                tbrBlue.Value = oTree.BlueChannelValue;

                tbxXmin.Text = oTree.Xmin.ToString();
                tbxXmax.Text = oTree.Xmax.ToString();
                tbxYmin.Text = oTree.Ymin.ToString();
                tbxYmax.Text = oTree.Ymax.ToString();
            }
            oTreeView.ExpandAll();
        }

        private TreeNode GetTreeViewNodes(Node oNode)
        {
            TreeNode oNewTreeViewNode = new TreeNode();

            string sText = "";

            if (oNode.Operand == Operands.VALUE)
                sText = oNode.Value.ToString();
            else if (oNode.Operand == Operands.X)
                sText = "X";
            else if (oNode.Operand == Operands.Y)
                sText = "Y";
            else
                sText = oNode.Operator.ToString();

            oNewTreeViewNode.Text = sText;

            if (oNode.LeftChild != null)
            {
                oNewTreeViewNode.Nodes.Add(GetTreeViewNodes(oNode.LeftChild));
            }
            if (oNode.RightChild != null)
            {
                oNewTreeViewNode.Nodes.Add(GetTreeViewNodes(oNode.RightChild));
            }

            return oNewTreeViewNode;
        }

        private void btnForceReDraw_Click(object sender, EventArgs e)
        {
            ReDrawAll();
        }

        private void pbxBigPicture_Click(object sender, EventArgs e)
        {
            if (pbxBigPicture.Visible)
            {
                pbxBigPicture.Hide();
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (_iSelections.Count > 0 && SaveTreeDialog.ShowDialog() == DialogResult.OK)
            {
                System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(_oPopulation[_iSelections[0]].GetType());

                Stream stream = File.Open(SaveTreeDialog.FileName, FileMode.Create);

                x.Serialize(stream, _oPopulation[_iSelections[0]]);

                stream.Close();
            }
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            if (OpenTreeDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    ClearSelections();

                    _oPopulation.Clear();

                    Tree oLoadedTree = new Tree();

                    System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(oLoadedTree.GetType());

                    Stream stream = File.Open(OpenTreeDialog.FileName, FileMode.Open);

                    oLoadedTree = (Tree)x.Deserialize(stream);

                    stream.Close();

                    _oPopulation.Add(oLoadedTree);

                    ReDrawAll();
                }
                catch (Exception)
                {
                    MessageBox.Show("Loading failed.");
                }
            }
        }

        private void tbxCoordinates_TextChanged(object sender, EventArgs e)
        {
            double dParsed = double.NaN;

            if (double.TryParse((sender as TextBox).Text, out dParsed))
            {
                if (_iSelections.Count > 0)
                {
                    int iSelected = _iSelections[_iSelections.Count - 1];
                    Tree oSelectedTree = _oPopulation[iSelected];

                    if (dParsed != double.PositiveInfinity && dParsed != double.NegativeInfinity && dParsed != double.NaN)
                    {
                        bool bReDraw = false;

                        if (sender == tbxXmin && dParsed != oSelectedTree.Xmin)
                        {
                            oSelectedTree.Xmin = dParsed;
                            bReDraw = true;
                        }
                        else if (sender == tbxXmax && dParsed != oSelectedTree.Xmax)
                        {
                            oSelectedTree.Xmax = dParsed;
                            bReDraw = true;
                        }
                        else if (sender == tbxYmin && dParsed != oSelectedTree.Ymin)
                        {
                            oSelectedTree.Ymin = dParsed;
                            bReDraw = true;
                        }
                        else if (sender == tbxYmax && dParsed != oSelectedTree.Ymax)
                        {
                            oSelectedTree.Ymax = dParsed;
                            bReDraw = true;
                        }

                        if (bReDraw)
                            DrawTree(oSelectedTree, (PictureBox)oTablePanel.Controls[iSelected].Controls[0]);
                    }
                }
            }
        }

        private void cbxColorFilter_CheckedChanged(object sender, EventArgs e)
        {
            if (_iSelections.Count > 0)
            {
                bool bNewState = (sender as CheckBox).Checked;

                int iSelected = _iSelections[_iSelections.Count - 1];
                Tree oSelectedTree = _oPopulation[iSelected];

                bool bReDraw = true;

                if (sender == cbxRed && bNewState != oSelectedTree.RedChannelModifier)
                {
                    oSelectedTree.RedChannelModifier = bNewState;
                    bReDraw = true;
                }
                else if (sender == cbxGreen && bNewState != oSelectedTree.GreenChannelModifier)
                {
                    oSelectedTree.GreenChannelModifier = bNewState;
                    bReDraw = true;
                }
                else if (sender == cbxBlue && bNewState != oSelectedTree.BlueChannelModifier)
                {
                    oSelectedTree.BlueChannelModifier = bNewState;
                    bReDraw = true;
                }

                if (bReDraw)
                    DrawTree(oSelectedTree, (PictureBox)oTablePanel.Controls[iSelected].Controls[0]);
            }
        }

        private void tbrColorFilter_ValueChanged(object sender, EventArgs e)
        {
            if (_iSelections.Count > 0)
            {
                int iNewValue = (sender as TrackBar).Value;

                int iSelected = _iSelections[_iSelections.Count - 1];
                Tree oSelectedTree = _oPopulation[iSelected];

                bool bReDraw = true;

                if (sender == tbrRed && iNewValue != oSelectedTree.RedChannelValue)
                {
                    oSelectedTree.RedChannelValue = iNewValue;
                    bReDraw = true;
                }
                else if (sender == tbrGreen && iNewValue != oSelectedTree.GreenChannelValue)
                {
                    oSelectedTree.GreenChannelValue = iNewValue;
                    bReDraw = true;
                }
                else if (sender == tbrBlue && iNewValue != oSelectedTree.BlueChannelValue)
                {
                    oSelectedTree.BlueChannelValue = iNewValue;
                    bReDraw = true;
                }

                if (bReDraw)
                    DrawTree(oSelectedTree, (PictureBox)oTablePanel.Controls[iSelected].Controls[0]);
            }
        }

        private void btnSaveBitmap_Click(object sender, EventArgs e)
        {
            PictureBox oTempBox = new PictureBox();
            oTempBox.Height = Convert.ToInt32(tbxHeight.Text);
            oTempBox.Width = Convert.ToInt32(tbxWidth.Text);

            if (_iSelections.Count > 0)
            {
                DrawTree(_oPopulation[_iSelections[0]], oTempBox);

                if (SavePictureDialog.ShowDialog() == DialogResult.OK)
                {
                    oTempBox.Image.Save(SavePictureDialog.FileName);
                }
            }
        }

        private void tbxHeightWidth_TextChanged(object sender, EventArgs e)
        {
            uint iValue = 1000;

            if (!uint.TryParse((sender as TextBox).Text, out iValue))
                iValue = 1000;

            (sender as TextBox).Text = iValue.ToString();
        }

        private List<Bitmap> oAnimation = new List<Bitmap>();
        private int _iAnimationFrameCount = 0;
        private int _iAnimationFPS = 0;
        private int _iAnimationRunFrameCounter = 0;
        private Tree _oAnimationTree;
        private string _sPreAnimateYmin = "";
        private string _sPreAnimateYmax = "";
        private string _sPreAnimateXmin = "";
        private string _sPreAnimateXmax = "";
        private Random _oRandom = new Random();

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (AutoSearchTimer.Enabled)
            {
                bDoStopAutoGA = true;
            }
            else
            {
                oRenderer.Stop();
                _iAnimationFrameCount = 1;

                _iAnimationRunFrameCounter = oAnimation.Count - 1;
                cbxAnimateFullWindow.Checked = false;
            }
        }

        private void btnCross_Click(object sender, EventArgs e)
        {
            if (_iSelections.Count > 1)
            {
                List<Tree> oNewPopulation = new List<Tree>();

                Tree oParentTree1 = _oPopulation[_iSelections[0]];
                Tree oParentTree2 = _oPopulation[_iSelections[1]];

                oNewPopulation.Add(oParentTree1);
                oNewPopulation.Add(oParentTree2);

                ClearSelections();

                for (int i = 0; i < 9; i++)
                {
                    Tree oChild1;
                    Tree oChild2;

                    Tree.Cross(oParentTree1, oParentTree2, out oChild1, out oChild2);

                    oNewPopulation.Add(oChild1);
                    oNewPopulation.Add(oChild2);
                }

                _oPopulation = oNewPopulation;

                ReDrawAll();
            }
        }

        private void btnMutate_Click(object sender, EventArgs e)
        {
            if (_iSelections.Count > 0)
            {
                List<Tree> oNewPopulation = new List<Tree>();

                Tree oParentTree = _oPopulation[_iSelections[0]];

                oNewPopulation.Add(oParentTree);

                ClearSelections();

                for (int i = 0; i < 19; i++)
                {
                    Tree oNewTree = oParentTree;

                    int iTargetMutationCount = _oRandom.Next(Properties.Settings.Default.MutateAmountMin, Properties.Settings.Default.MutateAmountMax + 1);
                    int iCounter = 0;

                    while (iCounter < iTargetMutationCount)
                    {
                        iCounter++;

                        oNewTree = oNewTree.Mutate();
                    }

                    Console.WriteLine(iCounter);

                    oNewPopulation.Add(oNewTree);
                }

                _oPopulation = oNewPopulation;

                ReDrawAll();
            }
        }

        private void btnAnimate_Click(object sender, EventArgs e)
        {
            if (_iSelections.Count >= 0)
            {
                _oAnimationTree = _oPopulation[_iSelections[0]];

                oAnimation.Clear();

                _iAnimationFrameCount = 1;

                Int32.TryParse(textBox1.Text, out _iAnimationFrameCount);

                _iAnimationFPS = 10;

                Int32.TryParse(textBox2.Text, out _iAnimationFPS);

                _iAnimationFPS = 1000 / _iAnimationFPS;

                _iAnimationRunFrameCounter = 0;

                oTablePanel.Enabled = false;
                gbxGA.Enabled = false;
                gbxCoordinates.Enabled = false;
                gbxDrawing.Enabled = false;
                gbxAnimate.Enabled = false;

                _sPreAnimateYmin = tbxYmin.Text;
                _sPreAnimateYmax = tbxYmax.Text;
                _sPreAnimateXmin = tbxXmin.Text;
                _sPreAnimateXmax = tbxXmax.Text;

                oProgressBar.Maximum = _iAnimationFrameCount;
                oProgressBar.Minimum = 0;
                oProgressBar.Value = 0;
                oProgressBar.Show();

                btnPlayAnimationAgain.Enabled = true;
                btnExport.Enabled = true;

                AnimationTimer.Interval = 10;
                AnimationTimer.Enabled = true;
            }
        }

        private void btnPlayAnimationAgain_Click(object sender, EventArgs e)
        {
            if (oAnimation.Count >= 0)
            {
                _iAnimationFrameCount = 0;
                _iAnimationRunFrameCounter = 0;
                oTablePanel.Enabled = false;
                gbxGA.Enabled = false;
                gbxCoordinates.Enabled = false;
                gbxDrawing.Enabled = false;
                gbxAnimate.Enabled = false;

                if (cbxAnimateFullWindow.Checked)
                    pbxBigPicture.Show();

                AnimationTimer.Interval = _iAnimationFPS;
                AnimationTimer.Start();
            }
        }

        private void AnimationTimer_Tick(object sender, EventArgs e)
        {
            if (_iAnimationFrameCount > 0)
            {
                _iAnimationFrameCount--;

                Add(tbxXmin);
                Subst(tbxXmax);
                Add(tbxYmin);
                Subst(tbxYmax);

                if (cbxAnimateFullWindow.Checked)
                {
                    Bitmap oBitmap = DrawTree(_oAnimationTree, pbxBigPicture);
                    pictureBox20.Image = oBitmap;
                    oAnimation.Add(oBitmap);
                }
                else
                {
                    oAnimation.Add(DrawTree(_oAnimationTree, pictureBox20));
                }


                if (_iAnimationFrameCount == 0)
                {
                    if (cbxAnimateFullWindow.Checked)
                        pbxBigPicture.Show();

                    AnimationTimer.Interval = _iAnimationFPS;

                    oProgressBar.Hide();
                }

                oProgressBar.Increment(1);
            }

            if (_iAnimationFrameCount <= 0)
            {
                if (cbxAnimateFullWindow.Checked)
                    pbxBigPicture.Image = oAnimation[_iAnimationRunFrameCounter];
                else
                    pictureBox20.Image = oAnimation[_iAnimationRunFrameCounter];

                _iAnimationRunFrameCounter++;

                if (_iAnimationRunFrameCounter >= oAnimation.Count - 1)
                {
                    AnimationTimer.Stop();
                    pbxBigPicture.Hide();

                    oTablePanel.Enabled = true;
                    gbxGA.Enabled = true;
                    gbxCoordinates.Enabled = true;
                    gbxDrawing.Enabled = true;
                    gbxAnimate.Enabled = true;

                    tbxYmin.Text = _sPreAnimateYmin;
                    tbxYmax.Text = _sPreAnimateYmax;
                    tbxXmin.Text = _sPreAnimateXmin;
                    tbxXmax.Text = _sPreAnimateXmax;

                    DrawTree(_oPopulation[0], (PictureBox)oTablePanel.Controls[0].Controls[0]);

                    oProgressBar.Hide();
                }
            }
        }

        private void Add(TextBox tbx)
        {
            double dValue = Convert.ToDouble(tbx.Text);

            tbx.Text = (dValue + Math.Abs(dValue / trackBar1.Value)).ToString();
        }

        private void Subst(TextBox tbx)
        {
            double dValue = Convert.ToDouble(tbx.Text);

            tbx.Text = (dValue - Math.Abs(dValue / trackBar1.Value)).ToString();
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            if (oAnimation.Count >= 0 && SaveAnimationDialog.ShowDialog() == DialogResult.OK)
            {
                if (SaveAnimationDialog.FilterIndex == 2)
                {
                    string sFileName = SaveAnimationDialog.FileName.Substring(0, SaveAnimationDialog.FileName.Length - 4);
                    
                    for (int picCount = 0; picCount < oAnimation.Count; picCount++)
                    {
                        oAnimation[picCount].Save(sFileName + picCount.ToString() + ".bmp");
                    }
                }
                else
                {
                    /* Special thanks to Rick van den Bosch for this code of creating the animated GIF.
                     * This code has been borrowed by the permission of the original author.
                     * Original code is available from here: http://bloggingabout.net/blogs/rick/archive/2005/05/10/3830.aspx
                     */
                    FileStream oStream = new FileStream(SaveAnimationDialog.FileName, FileMode.Create);

                    MemoryStream memoryStream;
                    BinaryWriter binaryWriter;
                    Image image;
                    Byte[] buf1;
                    Byte[] buf2;
                    Byte[] buf3;
                    //Variable declaration

                    memoryStream = new MemoryStream();
                    buf2 = new Byte[19];
                    buf3 = new Byte[8];
                    buf2[0] = 33;  //extension introducer
                    buf2[1] = 255; //application extension
                    buf2[2] = 11;  //size of block
                    buf2[3] = 78;  //N
                    buf2[4] = 69;  //E
                    buf2[5] = 84;  //T
                    buf2[6] = 83;  //S
                    buf2[7] = 67;  //C
                    buf2[8] = 65;  //A
                    buf2[9] = 80;  //P
                    buf2[10] = 69; //E
                    buf2[11] = 50; //2
                    buf2[12] = 46; //.
                    buf2[13] = 48; //0
                    buf2[14] = 3;  //Size of block
                    buf2[15] = 1;  //
                    buf2[16] = 0;  //
                    buf2[17] = 0;  //
                    buf2[18] = 0;  //Block terminator
                    buf3[0] = 33;  //Extension introducer
                    buf3[1] = 249; //Graphic control extension
                    buf3[2] = 4;   //Size of block
                    buf3[3] = 9;   //Flags: reserved, disposal method, user input, transparent color
                    buf3[4] = 0;  //Delay time low byte
                    buf3[5] = 1;   //Delay time high byte
                    buf3[6] = 255; //Transparent color index
                    buf3[7] = 0;   //Block terminator
                    binaryWriter = new BinaryWriter(oStream);

                    for (int picCount = 0; picCount < oAnimation.Count; picCount++)
                    {
                        image = oAnimation[picCount];
                        image.Save(memoryStream, ImageFormat.Gif);
                        buf1 = memoryStream.ToArray();

                        if (picCount == 0)
                        {
                            //only write these the first time....
                            binaryWriter.Write(buf1, 0, 781); //Header & global color table
                            binaryWriter.Write(buf2, 0, 19); //Application extension
                        }

                        binaryWriter.Write(buf3, 0, 8); //Graphic extension
                        binaryWriter.Write(buf1, 789, buf1.Length - 790); //Image data

                        if (picCount == oAnimation.Count - 1)
                        {
                            //only write this one the last time....
                            binaryWriter.Write(";"); //Image terminator
                        }

                        memoryStream.SetLength(0);
                    }
                    binaryWriter.Close();
                    oStream.Close();
                }
            }
        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            lblChangeValue.Text = (1 / (double)trackBar1.Value).ToString();
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new Settings()).ShowDialog();

            trackBar1.Maximum = Properties.Settings.Default.AnimationStepMax;
        }

        private void loadExamplesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClearSelections();

            _oPopulation.Clear();

            int iCounter = 1;

            try
            {
                for (; iCounter <= 20; iCounter++)
                {
                    Tree oLoadedTree = new Tree();

                    System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(oLoadedTree.GetType());

                    Stream stream = File.Open("Examples\\" + iCounter + ".xml", FileMode.Open);

                    oLoadedTree = (Tree)x.Deserialize(stream);

                    stream.Close();

                    _oPopulation.Add(oLoadedTree);
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show("Loading failed in Example" + iCounter + ".xml.\n" + exc.Message);
            }

            ReDrawAll();
        }

        private void btnMenu_Click(object sender, EventArgs e)
        {
            MainMenu.Show(Cursor.Position);
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            (new AboutBox()).ShowDialog();
        }

        Bitmap oTargetImage = null;

        private void btnAutoGALoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog oOpener = new OpenFileDialog();

            if (oOpener.ShowDialog() == DialogResult.OK)
            {
                oTargetImage = (Bitmap)Bitmap.FromFile(oOpener.FileName);

                if (oTargetImage.Width != 100 || oTargetImage.Height != 100)
                {
                    Bitmap oLoadedImage = (Bitmap)oTargetImage.Clone();

                    oTargetImage = new Bitmap(100, 100);
                    Graphics Scaler = Graphics.FromImage(oTargetImage);

                    Scaler.DrawImage(oLoadedImage, new Rectangle(0, 0, 100, 100));
                }

                pictureBoxAuto1.Image = oTargetImage;

                btnAutoGASort.Enabled = true;
                btnAutoGAStart.Enabled = true;
            }
        }

        private void btnAutoGASort_Click(object sender, EventArgs e)
        {
            bCalculateFitness = true;

            ReDrawAllInSameThread();

            _oPopulation.Sort();

            bCalculateFitness = false;

            ReDrawAllInSameThread();
        }

        private void ReDrawAllInSameThread()
        {
            for (int i = 0; i < 20; i++)
            {
                DrawTree(_oPopulation[i], (PictureBox)oTablePanel.Controls[i].Controls[0]); //Draws the tree and places it to to corresponding picturebox

                //Console.WriteLine(i + ": " + _oPopulation[i].Fitness);
            }
        }

        private void btnAutoGAStart_Click(object sender, EventArgs e)
        {
            oAutoGAPanel.Visible = true;
            lblAutoGATarget.Visible = true;
            oTablePanel.Enabled = false;
            gbxAnimate.Enabled = false;
            gbxCoordinates.Enabled = false;
            gbxFilters.Visible = false;
            gbxDrawing.Enabled = false;
            gbxManualGA.Enabled = false;
            oTreeView.Visible = false;
            gbxAutomaticGA.Enabled = false;
            btnMenu.Enabled = false;
            lblAutoGARound.Visible = true;
            lblAutoGARoundText.Visible = true;

            bDoStopAutoGA = false;
            bCalculateFitness = true;

            ClearSelections();

            _oBestPopulation = new List<Tree>();
            fLastBest = 0;
            iResetCounter = 0;
            iTotalSameCouter = 0;
            iRound = 0;

            AutoSearchTimer.Enabled = true;
        }

        private List<Tree> _oBestPopulation = new List<Tree>();

        float fLastBest = 0;
        int iResetCounter = 0;
        int iTotalSameCouter = 0;
        int iRound = 0;
        bool bDoStopAutoGA = false;
        bool bCalculateFitness = false;

        private void AutoSearchTimer_Tick(object sender, EventArgs e)
        {
            if (bDoStopAutoGA)
            {
                AutoSearchTimer.Enabled = false;

                ReDrawAllInSameThread();

                _oPopulation.Sort();

                if (_oBestPopulation.Count > 0)
                {
                    List<Tree> _oOldPopulation = new List<Tree>(_oPopulation);

                    _oPopulation.Clear();
                    _oPopulation.AddRange(_oBestPopulation);

                    for (int i = _oPopulation.Count; i < 20; i++)
                    {
                        _oPopulation.Add(_oOldPopulation[_oOldPopulation.Count - 1]);
                        _oOldPopulation.RemoveAt(_oOldPopulation.Count - 1);
                    }

                    ReDrawAllInSameThread();

                    _oPopulation.Sort();

                    for (int i = 1; i < 10; i++)
                    {
                        ((PictureBox)oAutoGAPanel.Controls[9 - i].Controls[0]).Image = null;
                    }
                }

                oAutoGAPanel.Visible = false;
                lblAutoGATarget.Visible = false;
                oTablePanel.Enabled = true;
                gbxAnimate.Enabled = true;
                gbxCoordinates.Enabled = true;
                gbxFilters.Visible = true;
                gbxDrawing.Enabled = true;
                gbxManualGA.Enabled = true;
                oTreeView.Visible = true;
                gbxAutomaticGA.Enabled = true;
                btnMenu.Enabled = true;

                bCalculateFitness = false;

                lblAutoGARound.Visible = false;
                lblAutoGARoundText.Visible = false;
            }
            else
            {
                lblAutoGARound.Text = iRound.ToString();

                if (iRound % 20 == 0)
                {
                    AutoSearchTimer.Interval = 5000;
                }
                else
                {
                    AutoSearchTimer.Interval = 1000;
                }

                if (iTotalSameCouter == 50)
                {
                    ReDrawAllInSameThread();

                    _oPopulation.Sort();

                    _oBestPopulation.Add(_oPopulation[19]);

                    if (_oBestPopulation.Count >= 10)
                    {
                        _oPopulation = _oBestPopulation;

                        _oBestPopulation = new List<Tree>();

                        for (int i = _oPopulation.Count; i < 20; i++)
                        {
                            _oPopulation.Add(Tree.CreateRandomTree());
                        }

                        iRound = 0;
                        fLastBest = 0;
                        iTotalSameCouter = 0;
                    }
                    else
                    {
                        DrawTree(_oPopulation[19], (PictureBox)oAutoGAPanel.Controls[_oBestPopulation.Count - 1].Controls[0]);
                        _oPopulation = new List<Tree>();

                        ClearSelections();

                        for (int iCount = 0; iCount < 20; iCount++)
                        {
                            _oPopulation.Add(Tree.CreateRandomTree());
                        }
                        iRound = 0;
                        fLastBest = 0;
                        iTotalSameCouter = 0;
                    }
                }
                else
                {
                    if (iResetCounter <= 20)
                    {
                        iRound++;

                        ReDrawAllInSameThread();

                        _oPopulation.Sort();

                        Console.WriteLine(iRound + ": " + _oPopulation[19].Fitness + " - " + iResetCounter + " - " + iTotalSameCouter + " - " + _oBestPopulation.Count);

                        if (fLastBest != _oPopulation[19].Fitness)
                        {
                            iTotalSameCouter = 0;
                            fLastBest = _oPopulation[19].Fitness;
                            iResetCounter = 0;
                        }
                        else
                        {
                            iResetCounter++;
                            iTotalSameCouter++;
                        }

                        if (_oPopulation[19].Fitness == 0)
                        {
                            bDoStopAutoGA = true;
                            MessageBox.Show("Identical image found.");
                            bDoStopAutoGA = true;
                        }

                        List<Tree> oNewPopulation = new List<Tree>();
                        oNewPopulation.Add(_oPopulation[19]);
                        oNewPopulation.Add(_oPopulation[18]);
                        //oNewPopulation.Add(_oPopulation[17]);
                        //oNewPopulation.Add(_oPopulation[16]);

                        for (int i = 0; i < 9; i++)
                        {
                            Tree oParentTree1 = _oPopulation[_oRandom.Next(18, 20)];
                            Tree oParentTree2 = null;

                            do
                            {
                                oParentTree2 = _oPopulation[_oRandom.Next(18, 20)];
                            }
                            while (oParentTree2 != null && oParentTree2 != oParentTree1);

                            Tree oChild1;
                            Tree oChild2;

                            Tree.Cross(oParentTree1, oParentTree2, out oChild1, out oChild2);

                            oNewPopulation.Add(oChild1);
                            oNewPopulation.Add(oChild2);
                        }

                        for (int i = 0; i < 10; i++)
                        {
                            int iPosition = _oRandom.Next(0, 18);
                            Tree oNewTree = oNewPopulation[iPosition];
                            oNewPopulation.RemoveAt(iPosition);

                            int iTargetMutationCount = _oRandom.Next(Properties.Settings.Default.MutateAmountMin, Properties.Settings.Default.MutateAmountMax + 1);
                            int iCounter = 0;

                            while (iCounter < iTargetMutationCount)
                            {
                                iCounter++;

                                oNewTree = oNewTree.Mutate();
                            }

                            //Console.WriteLine(iCounter);

                            oNewPopulation.Add(oNewTree);
                        }

                        _oPopulation = oNewPopulation;

                        //button3_Click(null, null);
                    }
                    else
                    {
                        ReDrawAllInSameThread();

                        _oPopulation.Sort();

                        //fLastBest = 0;
                        iResetCounter = 15;

                        Tree oBest = _oPopulation[19];

                        _oPopulation = new List<Tree>();

                        ClearSelections();

                        for (int iCount = 0; iCount < 19; iCount++)
                        {
                            _oPopulation.Add(Tree.CreateRandomTree());
                        }

                        _oPopulation.Add(oBest);
                    }
                }
            }
        }
    }
}